package com.boboPlanet.filter;

import com.boboPlanet.comm.context.LoginUserContext;
import com.boboPlanet.comm.enums.GatewayConstance;
import com.boboPlanet.dao.GatewayMapper;
import com.boboPlanet.enums.GatewayErrorEnum;
import com.boboPlanet.service.PageExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Description: TODO 用户鉴权（认证）过滤器 第一个过滤器链
 * @Author: mis_wu
 * @Date: 2023/6/20
 * @Company planet
 * 过滤器链执行顺序： 0、TraceLogFilter -> 1、RouteControlFilter ->StripPrefixFilter -> 2、JwtCheckFilter ->
 *                 3、AuthorizationFilter -> 4、GrayLoadBalancerFilter
 **/
@Component
@Slf4j
public class AuthorizationFilter implements GlobalFilter, Ordered {

    @Value("${server.port}")
    private String serverPort;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private GatewayMapper gatewayMapper;

    @Resource
    private PageExceptionHandler pageExceptionHandler;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> getParams = request.getQueryParams();
        //获取响应
        ServerHttpResponse response = exchange.getResponse();
        //请求路径
        String requestPath = request.getURI().getPath();
        log.info("request into gateway authorizationFilter, current path is: {}", requestPath);
        String contentType = request.getHeaders().getFirst("Content-Type");
        String reqMethod = Objects.requireNonNull(exchange.getRequest().getMethod()).name();

        //上一个过滤器执行结果
        String allow = request.getHeaders().getFirst(GatewayConstance.ALLOW_FILTER);
        if (String.valueOf(true).equals(allow)){
            return chain.filter(exchange);
        }

        //文件上传忽略
        if (!StringUtils.isEmpty(contentType) && contentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            return chain.filter(exchange);
        }
//        if (HttpMethod.POST.name().equals(reqMethod) || HttpMethod.PUT.name().equals(reqMethod)) {
//            try {
//                return DataBufferUtils.join(exchange.getRequest().getBody())
//                        .flatMap(dataBuffer -> {
//                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
//                            dataBuffer.read(bytes);
//                            String bodyString = new String(bytes, StandardCharsets.UTF_8);
//                            pageExceptionHandler.requestLogPrint(requestPath,reqMethod,getParams,bodyString);
//                            if (LOGIN_PATH.equals(requestPath) && GatewayConstance.POST_REQUEST.equals(reqMethod)){
//                                if (StringUtils.isBlank(bodyString)){
//                                    return pageExceptionHandler.pageExceptionHandler(response, GatewayErrorEnum.AUTHORIZATION_TOKEN.getMsg());
//                                }
//                                String loginKey = (String) JSON.parseObject(bodyString).get(LOGIN_ACCOUNT_FILED);
//                                Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(loginKey);
//                                if (!userMap.isEmpty()){
//                                    return pageExceptionHandler.pageExceptionHandler(response, GatewayErrorEnum.USER_STATUS_IS_LOGIN.getMsg());
//                                }
//                                Boolean loginLock = stringRedisTemplate.opsForValue().setIfAbsent(loginKey,"user-login-check",3, TimeUnit.SECONDS);
//                                if (Boolean.FALSE.equals(loginLock)){
//                                    return pageExceptionHandler.pageExceptionHandler(response, GatewayErrorEnum.LOGIN_OPE_QUEST.getMsg());
//                                }
//                            }
//                            exchange.getAttributes().put("request.body", bodyString);
//
//                            DataBufferUtils.release(dataBuffer);
//                            Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
//                                DataBuffer buffer = exchange.getResponse().bufferFactory().allocateBuffer(bytes.length).write(bytes);
//                                return Mono.just(buffer);
//                            });
//
//                            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
//                                    exchange.getRequest()) {
//                                @NotNull
//                                @Override
//                                public Flux<DataBuffer> getBody() {
//                                    return cachedFlux;
//                                }
//                            };
//                            return chain.filter(exchange.mutate().request(mutatedRequest).build());
//                        });
//            } catch (Exception e) {
//                log.error(requestPath + e.getMessage(), e);
//                return chain.filter(exchange);
//            }
//        }
        //GET 请求日志打印
        if (HttpMethod.GET.name().equals(reqMethod)) {
            pageExceptionHandler.requestLogPrint(requestPath,reqMethod,getParams,null);
        }

        //获取token认证
        String token = request.getHeaders().getFirst(GatewayConstance.REQUEST_HEADER_TOKEN);
        if (StringUtils.isBlank(token)){
            return pageExceptionHandler.pageExceptionHandler(response,HttpStatus.NON_AUTHORITATIVE_INFORMATION,  GatewayErrorEnum.AUTHORIZATION_TOKEN.getMsg());
        }

        //获取redis用户信息
        Map<Object,Object> authorizationInfo = stringRedisTemplate.opsForHash().entries(token);
        if (authorizationInfo.isEmpty()){
            return pageExceptionHandler.pageExceptionHandler(response,HttpStatus.NON_AUTHORITATIVE_INFORMATION,  GatewayErrorEnum.USER_LOGIN_ERROR.getMsg());
        }
        //校验用户是否存在
        if (gatewayMapper.userIsExist(token) <= 0){
            return pageExceptionHandler.pageExceptionHandler(response,HttpStatus.NON_AUTHORITATIVE_INFORMATION,  GatewayErrorEnum.AUTHORIZATION_TOKEN.getMsg());
        }

        //LoginUserContext.mock();

        request = exchange.getRequest().mutate().header(GatewayConstance.SERVER_PORT, serverPort).build();
        log.info("into AuthorizationFilter, authorization login user info!!!");
        return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
        return 3;
    }
}
